Analogy: making a schedule using the .ics format
Analogy: making a schedule using the .ics format
Analogy: making a schedule using a google calendar
Analogy: making a schedule using a google calendar
easy to change
You can make code that's hard to understand and hard to change…
Or you can make code that's easy to understand and easy to change.
Let's illustrate the principles of clean code [CC] by example.
First example:
w = x2 - x1
First example:
w = x2 - x1
w, x1 and x2?First example:
w = x2 - x1
w, x1 and x2?First example:
w = x2 - x1
w, x1 and x2?width = x_right - x_left
[CC1] Give names that reveal the purpose of things.
1 | width = x_right - x_left
|
Next:
1 | width = x_right - x_left + 10
|
Next:
1 | width = x_right - x_left + 10
|
Where does '10' come from?
What does it represent?
Can I change it?
Next:
1 | width = x_right - x_left + 10
|
Where does '10' come from?
What does it represent?
Can I change it?
1 | width = x_right - x_left + 2 * horizontal_margin
|
Next:
1 | width = x_right - x_left + 10
|
Where does '10' come from?
What does it represent?
Can I change it?
1 | width = x_right - x_left + 2 * horizontal_margin
|
[CC1] Replace magic numbers with named variables, parameters, or constants
[CC1] Replace magic numbers…
1 2 | def width_with_margins(x_right, x_left):
return x_right - x_left + 10
|
[CC1] Replace magic numbers…
1 2 | def width_with_margins(x_right, x_left):
return x_right - x_left + 10
|
…with named parameters
1 2 | def width_with_margins(x_right, x_left, horizontal_margin=5):
return x_right - x_left + 2 * horizontal_margin
|
[CC1] Replace magic numbers…
1 2 | def width_with_margins(x_right, x_left):
return x_right - x_left + 10
|
…with named parameters
1 2 | def width_with_margins(x_right, x_left, horizontal_margin=5):
return x_right - x_left + 2 * horizontal_margin
|
[CC1] Replace magic numbers…
1 | width = width * 0.3937007874
|
[CC1] Replace magic numbers…
1 2 | def width_with_margins(x_right, x_left):
return x_right - x_left + 10
|
…with named parameters
1 2 | def width_with_margins(x_right, x_left, horizontal_margin=5):
return x_right - x_left + 2 * horizontal_margin
|
[CC1] Replace magic numbers…
1 | width = width * 0.3937007874
|
…with named constants
1 | width_inches = width_cm * INCHES_PER_CENTIMETER
|
Note: magic numbers are not necessarily numbers!
PURPLE_HEX = "#6A0DAD"
Example from a past lecture:
1 | check_divisible(a, b)
|
Example from a past lecture:
1 | check_divisible(a, b)
|
What do you think this does?
Example from a past lecture:
1 | check_divisible(a, b)
|
What do you think this does?
The implementation:
1 2 3 | def check_divisible(n, divisor):
if (n % divisor == 0):
print(n, ' is divisible by ', divisor)
|
The implementation:
1 2 3 | def check_divisible(n, divisor):
if (n % divisor == 0):
print(n, ' is divisible by ', divisor)
|
Misleading name: I don't expect "something that checks" to print anything
A more accurate name:
1 2 3 | def print_if_divisible(n, divisor):
if (n % divisor == 0):
print(n, ' is divisible by ', divisor)
|
A more accurate name:
1 2 3 | def print_if_divisible(n, divisor):
if (n % divisor == 0):
print(n, ' is divisible by ', divisor)
|
[CC1] Function names should say what they do
[CC1] Function names should reveal side-effects (such as printing to the console)
Another function call:
1 | remove(l, n)
|
What do you think this does?
Another function call:
1 | remove(l, n)
|
What do you think this does? Ambiguous name:
l whose value is equal to n?l at index n?An unambiguous name:
1 | remove_list_element_at_index(l, i)
|
An unambiguous name:
1 | remove_list_element_at_index(l, i)
|
verb_keywords (the verb indicates what the function does, the keywords what parameters are expected)Two function calls:
1 2 | add_number(a , b)
add_list(c, d)
|
What do you think these do?
The implementation of the functions:
1 2 3 4 5 | def add_number(a , b):
return a + b
def add_list(l, e):
l.append(e)
|
The implementation of the functions:
1 2 3 4 5 | def add_number(a , b):
return a + b
def add_list(l, e):
l.append(e)
|
Confusing to use the same word "add" for the two functions:
add calculates the additionadd inserts an elementadd has no side effects, in the second, it does!A way to remove the confusion:
1 2 3 4 5 | def add_numbers(a , b):
return a + b
def append_element_to_list(e, l):
l.append(e)
|
A way to remove the confusion:
1 2 3 4 5 | def add_numbers(a , b):
return a + b
def append_element_to_list(e, l):
l.append(e)
|
Another function call:
1 | distance(couple_1, couple_2)
|
What is this about?
Another function call:
1 | distance(couple_1, couple_2)
|
What is this about? Unclear:
couple_1 and couple_2 represent?Another function call:
1 | distance(couple_1, couple_2)
|
Problem: we are mixing two levels of description
Example levels of description
A way to remove the confusion:
1 | distance(point_1, point_2)
|
A way to remove the confusion:
1 | distance(point_1, point_2)
|
A way to specify which kind of distance is computed:
1 2 | distance_between_points(point_1, point_2)
distance_between_intervals(interval_1, interval_2)
|
Let's revisit an earlier example:
1 2 3 | def print_if_divisible(n, divisor):
if (n % divisor == 0):
print(n, ' is divisible by ', divisor)
|
Let's revisit an earlier example:
1 2 3 | def print_if_divisible(n, divisor):
if (n % divisor == 0):
print(n, ' is divisible by ', divisor)
|
This function does two things:
Let's revisit an earlier example:
1 2 3 | def print_if_divisible(n, divisor):
if (n % divisor == 0):
print(n, ' is divisible by ', divisor)
|
This function does two things:
These are two conceptually distinct operations. There is no good reason for them to be done in the same function.
A solution:
1 2 | def is_divisible(n, divisor):
return (n % divisor == 0)
|
A solution:
1 2 | def is_divisible(n, divisor):
return (n % divisor == 0)
|
[CC2] Functions should do one thing
This solution has the added benefit to remove side-effects from the function.
Example code from a past student
display_dots_sparsity_cong do?CC2. Create functions that do one thing
Example code from a past student
Last principle of clean code…
Example from a past student:
1 2 3 4 | if shuffledtarg_dist[i][1] == 1: ### IF TARGET ###
# [some code ...]
elif shuffledtarg_dist[i][1] == 0: ### IF DISTRACTOR ###
# [some other code ...]
|
Example from a past student:
1 2 3 4 | if shuffledtarg_dist[i][1] == 1: ### IF TARGET ###
# [some code ...]
elif shuffledtarg_dist[i][1] == 0: ### IF DISTRACTOR ###
# [some other code ...]
|
if and elif?Example from a past student:
1 2 3 4 | if shuffledtarg_dist[i][1] == 1: ### IF TARGET ###
# [some code ...]
elif shuffledtarg_dist[i][1] == 0: ### IF DISTRACTOR ###
# [some other code ...]
|
if and elif?A first solution:
1 2 3 4 | if stimulus_type == STIMULUS_TYPE_TARGET:
# [some code ...]
elif stimulus_type == STIMULUS_TYPE_DISTRACTOR:
# [some other code ...]
|
A first solution:
1 2 3 4 | if stimulus_type == STIMULUS_TYPE_TARGET:
# [some code ...]
elif stimulus_type == STIMULUS_TYPE_DISTRACTOR:
# [some other code ...]
|
A first solution:
1 2 3 4 | if stimulus_type == STIMULUS_TYPE_TARGET:
# [some code ...]
elif stimulus_type == STIMULUS_TYPE_DISTRACTOR:
# [some other code ...]
|
An even better solution:
1 2 3 4 | if is_target(stimulus):
# [some code ...]
elif is_distractor(stimulus):
# [some other code ...]
|
Example from a past student:
1 2 3 4 | def distance_points(couple1,couple2):
"""Fonction controllant la distance entre nos points
pour notre ensemble de points aléatoires"""
return math.sqrt((couple1[0]-couple2[0])**2+(couple1[1]-couple2[1])**2)
|
Example from a past student:
1 2 3 4 | def distance_points(couple1,couple2):
"""Fonction controllant la distance entre nos points
pour notre ensemble de points aléatoires"""
return math.sqrt((couple1[0]-couple2[0])**2+(couple1[1]-couple2[1])**2)
|
An alternative:
1 | def distance_between_points(point_1, point_2)
|
Example from a past student:
1 | exp = design.Experiment("Task") #create and name new exp object
|
Example from a past student:
1 | exp = design.Experiment("Task") #create and name new exp object
|
The goal is to make code easy to understand and easy to change.
CC1 Use meaningful names.
Reveal purpose. Replace magic numbers. Say what functions do. Reveal/Avoid side-effects. Remove ambiguity. Use different words for different concepts. Use the appropriate level of description.
CC2 Create functions that do one thing.
CC3 DRY: Don't Repeat Yourself.
CC4 Explain yourself in code, not comments.
The goal is to make code easy to understand and easy to change.
CC1 Use meaningful names.
Reveal purpose. Replace magic numbers. Say what functions do. Reveal/Avoid side-effects. Remove ambiguity. Use different words for different concepts. Use the appropriate level of description.
CC2 Create functions that do one thing.
CC3 DRY: Don't Repeat Yourself.
CC4 Explain yourself in code, not comments.
| Clean Code | 1 |
|---|---|
| The goal of clean code is to make your code easy to understand and easy to change. | 2 |
| - | 3 |
| - | 4 |
| - | 5 |
| - | 6 |
| - | 7 |
| - | 8 |
| - | 9 |
| - | 10 |
| - | 11 |
| - | 12 |
| - | 13 |
| CC1. Use meaningful names | 14 |
| - | 15 |
| - | 16 |
| - | 17 |
| - | 18 |
| - | 19 |
| - | 20 |
| - | 21 |
| - | 22 |
| - | 23 |
| - | 24 |
| - | 25 |
| - | 26 |
| - | 27 |
| - | 28 |
| - | 29 |
| - | 30 |
| - | 31 |
| - | 32 |
| - | 33 |
| - | 34 |
| - | 35 |
| - | 36 |
| - | 37 |
| - | 38 |
| - | 39 |
| - | 40 |
| - | 41 |
| - | 42 |
| - | 43 |
| - | 44 |
| - | 45 |
| - | 46 |
| - | 47 |
| - | 48 |
| - | 49 |
| - | 50 |
| - | 51 |
| - | 52 |
| CC2. Create functions that do one thing | 53 |
| - | 54 |
| - | 55 |
| - | 56 |
| - | 57 |
| CC3. [Wait for it] | 58 |
| - | 59 |
| - | 60 |
| - | 61 |
| - | 62 |
| - | 63 |
| CC3. DRY: Don't Repeat Yourself | 64 |
| - | 65 |
| - | 66 |
| - | 67 |
| CC4. Explain yourself in code, not comments | 68 |
| - | 69 |
| - | 70 |
| - | 71 |
| - | 72 |
| - | 73 |
| - | 74 |
| - | 75 |
| - | 76 |
| - | 77 |
| - | 78 |
| - | 79 |
| - | 80 |
| Recap: Clean Code Principles | 81 |
| Recap: Clean Code Principles | 82 |
| Table of Contents | t |
|---|---|
| Exposé | ESC |
| Full screen slides | e |
| Presenter View | p |
| Source Files | s |
| Slide Numbers | n |
| Toggle screen blanking | b |
| Show/hide slide context | c |
| Notes | 2 |
| Help | h |